//
// Author:
//   Jb Evain (jbevain@gmail.com)
//
// Copyright (c) 2008 - 2015 Jb Evain
// Copyright (c) 2008 - 2011 Novell, Inc.
//
// Licensed under the MIT/X11 license.
//

using System;

namespace ILRuntime.Mono.Cecil.Cil
{

    public enum FlowControl
    {
        Branch,
        Break,
        Call,
        Cond_Branch,
        Meta,
        Next,
        Phi,
        Return,
        Throw,
    }

    public enum OpCodeType
    {
        Annotation,
        Macro,
        Nternal,
        Objmodel,
        Prefix,
        Primitive,
    }

    public enum OperandType
    {
        InlineBrTarget,
        InlineField,
        InlineI,
        InlineI8,
        InlineMethod,
        InlineNone,
        InlinePhi,
        InlineR,
        InlineSig,
        InlineString,
        InlineSwitch,
        InlineTok,
        InlineType,
        InlineVar,
        InlineArg,
        ShortInlineBrTarget,
        ShortInlineI,
        ShortInlineR,
        ShortInlineVar,
        ShortInlineArg,
    }

    public enum StackBehaviour
    {
        Pop0,
        Pop1,
        Pop1_pop1,
        Popi,
        Popi_pop1,
        Popi_popi,
        Popi_popi8,
        Popi_popi_popi,
        Popi_popr4,
        Popi_popr8,
        Popref,
        Popref_pop1,
        Popref_popi,
        Popref_popi_popi,
        Popref_popi_popi8,
        Popref_popi_popr4,
        Popref_popi_popr8,
        Popref_popi_popref,
        PopAll,
        Push0,
        Push1,
        Push1_push1,
        Pushi,
        Pushi8,
        Pushr4,
        Pushr8,
        Pushref,
        Varpop,
        Varpush,
    }

    public struct OpCode : IEquatable<OpCode>
    {

        readonly byte op1;
        readonly byte op2;
        readonly byte code;
        readonly byte flow_control;
        readonly byte opcode_type;
        readonly byte operand_type;
        readonly byte stack_behavior_pop;
        readonly byte stack_behavior_push;

        public string Name
        {
            get { return OpCodeNames.names[(int)Code]; }
        }

        public int Size
        {
            get { return op1 == 0xff ? 1 : 2; }
        }

        public byte Op1
        {
            get { return op1; }
        }

        public byte Op2
        {
            get { return op2; }
        }

        public short Value
        {
            get { return op1 == 0xff ? op2 : (short)((op1 << 8) | op2); }
        }

        public Code Code
        {
            get { return (Code)code; }
        }

        public FlowControl FlowControl
        {
            get { return (FlowControl)flow_control; }
        }

        public OpCodeType OpCodeType
        {
            get { return (OpCodeType)opcode_type; }
        }

        public OperandType OperandType
        {
            get { return (OperandType)operand_type; }
        }

        public StackBehaviour StackBehaviourPop
        {
            get { return (StackBehaviour)stack_behavior_pop; }
        }

        public StackBehaviour StackBehaviourPush
        {
            get { return (StackBehaviour)stack_behavior_push; }
        }

        internal OpCode(int x, int y)
        {
            op1 = (byte)((x >> 0) & 0xff);
            op2 = (byte)((x >> 8) & 0xff);
            code = (byte)((x >> 16) & 0xff);
            flow_control = (byte)((x >> 24) & 0xff);

            opcode_type = (byte)((y >> 0) & 0xff);
            operand_type = (byte)((y >> 8) & 0xff);
            stack_behavior_pop = (byte)((y >> 16) & 0xff);
            stack_behavior_push = (byte)((y >> 24) & 0xff);

            if (op1 == 0xff)
                OpCodes.OneByteOpCode[op2] = this;
            else
                OpCodes.TwoBytesOpCode[op2] = this;
        }

        public override int GetHashCode()
        {
            return Value;
        }

        public override bool Equals(object obj)
        {
            if (!(obj is OpCode))
                return false;

            OpCode opcode = (OpCode)obj;
            return op1 == opcode.op1 && op2 == opcode.op2;
        }

        public bool Equals(OpCode opcode)
        {
            return op1 == opcode.op1 && op2 == opcode.op2;
        }

        public static bool operator ==(OpCode one, OpCode other)
        {
            return one.op1 == other.op1 && one.op2 == other.op2;
        }

        public static bool operator !=(OpCode one, OpCode other)
        {
            return one.op1 != other.op1 || one.op2 != other.op2;
        }

        public override string ToString()
        {
            return Name;
        }
    }

    static class OpCodeNames
    {

        internal static readonly string[] names;

        static OpCodeNames()
        {
            byte[] table = new byte[] {
                3, 110, 111, 112,
                5, 98, 114, 101, 97, 107,
                7, 108, 100, 97, 114, 103, 46, 48,
                7, 108, 100, 97, 114, 103, 46, 49,
                7, 108, 100, 97, 114, 103, 46, 50,
                7, 108, 100, 97, 114, 103, 46, 51,
                7, 108, 100, 108, 111, 99, 46, 48,
                7, 108, 100, 108, 111, 99, 46, 49,
                7, 108, 100, 108, 111, 99, 46, 50,
                7, 108, 100, 108, 111, 99, 46, 51,
                7, 115, 116, 108, 111, 99, 46, 48,
                7, 115, 116, 108, 111, 99, 46, 49,
                7, 115, 116, 108, 111, 99, 46, 50,
                7, 115, 116, 108, 111, 99, 46, 51,
                7, 108, 100, 97, 114, 103, 46, 115,
                8, 108, 100, 97, 114, 103, 97, 46, 115,
                7, 115, 116, 97, 114, 103, 46, 115,
                7, 108, 100, 108, 111, 99, 46, 115,
                8, 108, 100, 108, 111, 99, 97, 46, 115,
                7, 115, 116, 108, 111, 99, 46, 115,
                6, 108, 100, 110, 117, 108, 108,
                9, 108, 100, 99, 46, 105, 52, 46, 109, 49,
                8, 108, 100, 99, 46, 105, 52, 46, 48,
                8, 108, 100, 99, 46, 105, 52, 46, 49,
                8, 108, 100, 99, 46, 105, 52, 46, 50,
                8, 108, 100, 99, 46, 105, 52, 46, 51,
                8, 108, 100, 99, 46, 105, 52, 46, 52,
                8, 108, 100, 99, 46, 105, 52, 46, 53,
                8, 108, 100, 99, 46, 105, 52, 46, 54,
                8, 108, 100, 99, 46, 105, 52, 46, 55,
                8, 108, 100, 99, 46, 105, 52, 46, 56,
                8, 108, 100, 99, 46, 105, 52, 46, 115,
                6, 108, 100, 99, 46, 105, 52,
                6, 108, 100, 99, 46, 105, 56,
                6, 108, 100, 99, 46, 114, 52,
                6, 108, 100, 99, 46, 114, 56,
                3, 100, 117, 112,
                3, 112, 111, 112,
                3, 106, 109, 112,
                4, 99, 97, 108, 108,
                5, 99, 97, 108, 108, 105,
                3, 114, 101, 116,
                4, 98, 114, 46, 115,
                9, 98, 114, 102, 97, 108, 115, 101, 46, 115,
                8, 98, 114, 116, 114, 117, 101, 46, 115,
                5, 98, 101, 113, 46, 115,
                5, 98, 103, 101, 46, 115,
                5, 98, 103, 116, 46, 115,
                5, 98, 108, 101, 46, 115,
                5, 98, 108, 116, 46, 115,
                8, 98, 110, 101, 46, 117, 110, 46, 115,
                8, 98, 103, 101, 46, 117, 110, 46, 115,
                8, 98, 103, 116, 46, 117, 110, 46, 115,
                8, 98, 108, 101, 46, 117, 110, 46, 115,
                8, 98, 108, 116, 46, 117, 110, 46, 115,
                2, 98, 114,
                7, 98, 114, 102, 97, 108, 115, 101,
                6, 98, 114, 116, 114, 117, 101,
                3, 98, 101, 113,
                3, 98, 103, 101,
                3, 98, 103, 116,
                3, 98, 108, 101,
                3, 98, 108, 116,
                6, 98, 110, 101, 46, 117, 110,
                6, 98, 103, 101, 46, 117, 110,
                6, 98, 103, 116, 46, 117, 110,
                6, 98, 108, 101, 46, 117, 110,
                6, 98, 108, 116, 46, 117, 110,
                6, 115, 119, 105, 116, 99, 104,
                8, 108, 100, 105, 110, 100, 46, 105, 49,
                8, 108, 100, 105, 110, 100, 46, 117, 49,
                8, 108, 100, 105, 110, 100, 46, 105, 50,
                8, 108, 100, 105, 110, 100, 46, 117, 50,
                8, 108, 100, 105, 110, 100, 46, 105, 52,
                8, 108, 100, 105, 110, 100, 46, 117, 52,
                8, 108, 100, 105, 110, 100, 46, 105, 56,
                7, 108, 100, 105, 110, 100, 46, 105,
                8, 108, 100, 105, 110, 100, 46, 114, 52,
                8, 108, 100, 105, 110, 100, 46, 114, 56,
                9, 108, 100, 105, 110, 100, 46, 114, 101, 102,
                9, 115, 116, 105, 110, 100, 46, 114, 101, 102,
                8, 115, 116, 105, 110, 100, 46, 105, 49,
                8, 115, 116, 105, 110, 100, 46, 105, 50,
                8, 115, 116, 105, 110, 100, 46, 105, 52,
                8, 115, 116, 105, 110, 100, 46, 105, 56,
                8, 115, 116, 105, 110, 100, 46, 114, 52,
                8, 115, 116, 105, 110, 100, 46, 114, 56,
                3, 97, 100, 100,
                3, 115, 117, 98,
                3, 109, 117, 108,
                3, 100, 105, 118,
                6, 100, 105, 118, 46, 117, 110,
                3, 114, 101, 109,
                6, 114, 101, 109, 46, 117, 110,
                3, 97, 110, 100,
                2, 111, 114,
                3, 120, 111, 114,
                3, 115, 104, 108,
                3, 115, 104, 114,
                6, 115, 104, 114, 46, 117, 110,
                3, 110, 101, 103,
                3, 110, 111, 116,
                7, 99, 111, 110, 118, 46, 105, 49,
                7, 99, 111, 110, 118, 46, 105, 50,
                7, 99, 111, 110, 118, 46, 105, 52,
                7, 99, 111, 110, 118, 46, 105, 56,
                7, 99, 111, 110, 118, 46, 114, 52,
                7, 99, 111, 110, 118, 46, 114, 56,
                7, 99, 111, 110, 118, 46, 117, 52,
                7, 99, 111, 110, 118, 46, 117, 56,
                8, 99, 97, 108, 108, 118, 105, 114, 116,
                5, 99, 112, 111, 98, 106,
                5, 108, 100, 111, 98, 106,
                5, 108, 100, 115, 116, 114,
                6, 110, 101, 119, 111, 98, 106,
                9, 99, 97, 115, 116, 99, 108, 97, 115, 115,
                6, 105, 115, 105, 110, 115, 116,
                9, 99, 111, 110, 118, 46, 114, 46, 117, 110,
                5, 117, 110, 98, 111, 120,
                5, 116, 104, 114, 111, 119,
                5, 108, 100, 102, 108, 100,
                6, 108, 100, 102, 108, 100, 97,
                5, 115, 116, 102, 108, 100,
                6, 108, 100, 115, 102, 108, 100,
                7, 108, 100, 115, 102, 108, 100, 97,
                6, 115, 116, 115, 102, 108, 100,
                5, 115, 116, 111, 98, 106,
                14, 99, 111, 110, 118, 46, 111, 118, 102, 46, 105, 49, 46, 117, 110,
                14, 99, 111, 110, 118, 46, 111, 118, 102, 46, 105, 50, 46, 117, 110,
                14, 99, 111, 110, 118, 46, 111, 118, 102, 46, 105, 52, 46, 117, 110,
                14, 99, 111, 110, 118, 46, 111, 118, 102, 46, 105, 56, 46, 117, 110,
                14, 99, 111, 110, 118, 46, 111, 118, 102, 46, 117, 49, 46, 117, 110,
                14, 99, 111, 110, 118, 46, 111, 118, 102, 46, 117, 50, 46, 117, 110,
                14, 99, 111, 110, 118, 46, 111, 118, 102, 46, 117, 52, 46, 117, 110,
                14, 99, 111, 110, 118, 46, 111, 118, 102, 46, 117, 56, 46, 117, 110,
                13, 99, 111, 110, 118, 46, 111, 118, 102, 46, 105, 46, 117, 110,
                13, 99, 111, 110, 118, 46, 111, 118, 102, 46, 117, 46, 117, 110,
                3, 98, 111, 120,
                6, 110, 101, 119, 97, 114, 114,
                5, 108, 100, 108, 101, 110,
                7, 108, 100, 101, 108, 101, 109, 97,
                9, 108, 100, 101, 108, 101, 109, 46, 105, 49,
                9, 108, 100, 101, 108, 101, 109, 46, 117, 49,
                9, 108, 100, 101, 108, 101, 109, 46, 105, 50,
                9, 108, 100, 101, 108, 101, 109, 46, 117, 50,
                9, 108, 100, 101, 108, 101, 109, 46, 105, 52,
                9, 108, 100, 101, 108, 101, 109, 46, 117, 52,
                9, 108, 100, 101, 108, 101, 109, 46, 105, 56,
                8, 108, 100, 101, 108, 101, 109, 46, 105,
                9, 108, 100, 101, 108, 101, 109, 46, 114, 52,
                9, 108, 100, 101, 108, 101, 109, 46, 114, 56,
                10, 108, 100, 101, 108, 101, 109, 46, 114, 101, 102,
                8, 115, 116, 101, 108, 101, 109, 46, 105,
                9, 115, 116, 101, 108, 101, 109, 46, 105, 49,
                9, 115, 116, 101, 108, 101, 109, 46, 105, 50,
                9, 115, 116, 101, 108, 101, 109, 46, 105, 52,
                9, 115, 116, 101, 108, 101, 109, 46, 105, 56,
                9, 115, 116, 101, 108, 101, 109, 46, 114, 52,
                9, 115, 116, 101, 108, 101, 109, 46, 114, 56,
                10, 115, 116, 101, 108, 101, 109, 46, 114, 101, 102,
                10, 108, 100, 101, 108, 101, 109, 46, 97, 110, 121,
                10, 115, 116, 101, 108, 101, 109, 46, 97, 110, 121,
                9, 117, 110, 98, 111, 120, 46, 97, 110, 121,
                11, 99, 111, 110, 118, 46, 111, 118, 102, 46, 105, 49,
                11, 99, 111, 110, 118, 46, 111, 118, 102, 46, 117, 49,
                11, 99, 111, 110, 118, 46, 111, 118, 102, 46, 105, 50,
                11, 99, 111, 110, 118, 46, 111, 118, 102, 46, 117, 50,
                11, 99, 111, 110, 118, 46, 111, 118, 102, 46, 105, 52,
                11, 99, 111, 110, 118, 46, 111, 118, 102, 46, 117, 52,
                11, 99, 111, 110, 118, 46, 111, 118, 102, 46, 105, 56,
                11, 99, 111, 110, 118, 46, 111, 118, 102, 46, 117, 56,
                9, 114, 101, 102, 97, 110, 121, 118, 97, 108,
                8, 99, 107, 102, 105, 110, 105, 116, 101,
                8, 109, 107, 114, 101, 102, 97, 110, 121,
                7, 108, 100, 116, 111, 107, 101, 110,
                7, 99, 111, 110, 118, 46, 117, 50,
                7, 99, 111, 110, 118, 46, 117, 49,
                6, 99, 111, 110, 118, 46, 105,
                10, 99, 111, 110, 118, 46, 111, 118, 102, 46, 105,
                10, 99, 111, 110, 118, 46, 111, 118, 102, 46, 117,
                7, 97, 100, 100, 46, 111, 118, 102,
                10, 97, 100, 100, 46, 111, 118, 102, 46, 117, 110,
                7, 109, 117, 108, 46, 111, 118, 102,
                10, 109, 117, 108, 46, 111, 118, 102, 46, 117, 110,
                7, 115, 117, 98, 46, 111, 118, 102,
                10, 115, 117, 98, 46, 111, 118, 102, 46, 117, 110,
                10, 101, 110, 100, 102, 105, 110, 97, 108, 108, 121,
                5, 108, 101, 97, 118, 101,
                7, 108, 101, 97, 118, 101, 46, 115,
                7, 115, 116, 105, 110, 100, 46, 105,
                6, 99, 111, 110, 118, 46, 117,
                7, 97, 114, 103, 108, 105, 115, 116,
                3, 99, 101, 113,
                3, 99, 103, 116,
                6, 99, 103, 116, 46, 117, 110,
                3, 99, 108, 116,
                6, 99, 108, 116, 46, 117, 110,
                5, 108, 100, 102, 116, 110,
                9, 108, 100, 118, 105, 114, 116, 102, 116, 110,
                5, 108, 100, 97, 114, 103,
                6, 108, 100, 97, 114, 103, 97,
                5, 115, 116, 97, 114, 103,
                5, 108, 100, 108, 111, 99,
                6, 108, 100, 108, 111, 99, 97,
                5, 115, 116, 108, 111, 99,
                8, 108, 111, 99, 97, 108, 108, 111, 99,
                9, 101, 110, 100, 102, 105, 108, 116, 101, 114,
                10, 117, 110, 97, 108, 105, 103, 110, 101, 100, 46,
                9, 118, 111, 108, 97, 116, 105, 108, 101, 46,
                5, 116, 97, 105, 108, 46,
                7, 105, 110, 105, 116, 111, 98, 106,
                12, 99, 111, 110, 115, 116, 114, 97, 105, 110, 101, 100, 46,
                5, 99, 112, 98, 108, 107,
                7, 105, 110, 105, 116, 98, 108, 107,
                3, 110, 111, 46,
                7, 114, 101, 116, 104, 114, 111, 119,
                6, 115, 105, 122, 101, 111, 102,
                10, 114, 101, 102, 97, 110, 121, 116, 121, 112, 101,
                9, 114, 101, 97, 100, 111, 110, 108, 121, 46,
            };

            names = new string[219];

            for (int i = 0, p = 0; i < names.Length; i++)
            {
                char[] buffer = new char[table[p++]];

                for (int j = 0; j < buffer.Length; j++)
                    buffer[j] = (char)table[p++];

                names[i] = new string(buffer);
            }
        }
    }
}
